#include "PikaStdDevice_GPIO.h"
#include "PikaStdDevice_common.h"

#define LOG __platform_printf



static pika_dev* _get_dev(PikaObj* self) {
    pika_dev* dev = PIKA_HAL_OBJ2DEV(self);
    if (NULL != dev) {
        return dev;
    }
    dev = pika_hal_open(PIKA_HAL_GPIO, obj_getStr(self, "pin"));
    if (NULL == dev) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open GPIO '%s' failed.\r\n",
                          obj_getStr(self, "pin"));
    }
    obj_setPtr(self, "pika_dev", dev);
    return dev;
}

void PikaStdDevice_GPIO_init(PikaObj* self) {
    obj_setInt(self, "isEnable", 0);
    // obj_setStr(self, "pin", "none");
    // obj_setStr(self, "mode", "out");
    // obj_setStr(self, "pull", "none");
    // TODO: 将mode和pull改成int类型
    #if 1
    obj_setInt(self, "mode", PIKA_HAL_GPIO_OPEN_DRAIN);
    obj_setInt(self, "pull", PIKA_HAL_GPIO_PULL_NONE);
    #endif
    obj_setInt(self, "isOn", 0);
    obj_setInt(self, "id", -999);
    obj_setPtr(self, "pika_dev", NULL);
    obj_setInt(self, "filter", PIKA_HAL_GPIO_EVENT_SIGNAL_FALLING);
    obj_setArg(self, "evt_cbk", NULL);
}

int PikaStdDevice_GPIO_getId(PikaObj* self) {
    return obj_getInt(self, "id");
}

void PikaStdDevice_GPIO_setId(PikaObj* self, int id) {
    obj_setInt(self, "id", id);
}

// class GPIO
void PikaStdDevice_GPIO___init__(PikaObj* self, char* pinName) {
    PikaStdDevice_GPIO_init(self);
    obj_setStr(self, "pin", pinName);
}



void PikaStdDevice_GPIO_disable(PikaObj* self) {
    obj_setInt(self, "isEnable", 0);
    pika_dev* dev = _get_dev(self);
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE);
}


void PikaStdDevice_GPIO_enable(PikaObj* self) {
    #if 1 
    obj_setInt(self, "isEnable", 1);
    pika_dev* dev = _get_dev(self);
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE);

    // int pull = obj_getInt(self, "pull");
    // int mode = obj_getInt(self, "mode");
    PikaStdDevice_GPIO_setPull(self, obj_getInt(self, "pull"));
    PikaStdDevice_GPIO_setMode(self, obj_getInt(self, "mode"));
    PikaStdDevice_GPIO_setIrq(self, obj_getArg(self, "evt_cbk"),obj_getInt(self, "filter"));
    #endif

}

void PikaStdDevice_GPIO_setIrq(PikaObj* self, Arg* eventCallback, int irq_filter) {
    PikaStdDevice_GPIO_setCallback(self, eventCallback, irq_filter);
}


void PikaStdDevice_GPIO_config(PikaObj* self, int mode, int pull, Arg* eventCallback, int irq_filter) {
    PikaStdDevice_GPIO_setPull(self, pull);
    PikaStdDevice_GPIO_setMode(self, mode);
    PikaStdDevice_GPIO_setIrq(self, eventCallback, irq_filter);
}

int PikaStdDevice_GPIO_getMode(PikaObj* self) {
    return obj_getInt(self, "mode");
}

int PikaStdDevice_GPIO_getPull(PikaObj* self) {
    return obj_getInt(self, "pull");
}

char* PikaStdDevice_GPIO_getPin(PikaObj* self) {
    return obj_getStr(self, "pin");
}

void PikaStdDevice_GPIO_low(PikaObj* self) {
    obj_setInt(self, "isOn", 0);
    pika_dev* dev = _get_dev(self);
    uint32_t val = 0;
    pika_hal_write(dev, &val, sizeof(val));
}

void PikaStdDevice_GPIO_high(PikaObj* self) {
    obj_setInt(self, "isOn", 1);
    pika_dev* dev = _get_dev(self);
    uint32_t val = 1;
    pika_hal_write(dev, &val, sizeof(val));
}

int PikaStdDevice_GPIO_read(PikaObj* self) {
    pika_dev* dev = _get_dev(self);
    uint32_t val = 0;
    pika_hal_read(dev, &val, sizeof(val));
    obj_setInt(self, "readBuff", val);
    return obj_getInt(self, "readBuff");
}


void PikaStdDevice_GPIO_write(PikaObj* self, int lv) {
    pika_dev* dev = _get_dev(self);
    uint32_t val = lv == 0 ? 0 : 1;
    obj_setInt(self, "isOn", val);
    pika_hal_write(dev, &val, sizeof(val));
}

void PikaStdDevice_GPIO_setMode(PikaObj* self, int mode) {
    // 增加开漏与中断模式，优化代码效率 -- 2024-11-13
    pika_hal_GPIO_config cfg = {0};
    LOG("<%s> mode: %d\n", __func__ ,mode);
    if (mode >= PIKA_HAL_GPIO_DIR_IN && mode <= PIKA_HAL_GPIO_IRQ){
        obj_setInt(self, "mode", mode);
        cfg.dir = mode;
    }
    else{
        obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM);
        obj_setSysOut(self, "[ERROR] GPIO mode should be 'OUT' or 'IN' or 'OD' or 'IRQ'.");

        return;
    }
    if (obj_getInt(self, "isEnable")){
        pika_dev* dev = _get_dev(self);
        pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg);
    }
    
}

void PikaStdDevice_GPIO_setPull(PikaObj* self, int pull) {
    // pull的实际设置从func<setMode>移到这里 -- 2024-11-12
    //优化代码效率
    LOG("<%s> pull: %d\n", __func__ ,pull);
    pika_hal_GPIO_config cfg = {0};
    if (pull >= PIKA_HAL_GPIO_PULL_NONE && pull <= PIKA_HAL_GPIO_PULL_DOWN){
        obj_setInt(self, "pull", pull);
        cfg.pull = pull;
    }
    else{
        obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM);
        obj_setSysOut(self, "[ERROR] GPIO pull should be 'UP', 'DOWN' or 'NONE'.");
        return;
    }

    if (obj_getInt(self, "isEnable")){
        pika_dev* dev = _get_dev(self);
        pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg);
    }

}

void PikaStdDevice_GPIO_setPin(PikaObj* self, char* pinName) {
    obj_setStr(self, "pin", pinName);
}

void PikaStdDevice_GPIO_setCallback(PikaObj* self,
                                    Arg* eventCallback,
                                    int filter) {
#if PIKA_EVENT_ENABLE

    obj_setInt(self, "filter", filter);
    obj_setArg(self, "evt_cbk", eventCallback);

    pika_dev* dev = _get_dev(self);
    _PikaStdDevice_setCallback(self, eventCallback, (uintptr_t)dev);
    /* regist event to pika_hal */
    pika_hal_GPIO_config cfg_cb = {0};
    cfg_cb.event_callback = _PikaStdDevice_GPIO_event_handler;
    cfg_cb.event_callback_filter = filter;
    cfg_cb.event_callback_ena = PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE;
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg_cb);
#else
    obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM);
    obj_setSysOut(self, "[ERROR] PIKA_EVENT_ENABLE is disabled.");
#endif
}



void PikaStdDevice_GPIO_setCallBack(PikaObj* self,
                                    Arg* eventCallback,
                                    int filter) {
    pika_platform_printf(
        "Warning: setCallBack is deprecated, use "
        "setCallback instead.\r\n");
    PikaStdDevice_GPIO_setCallback(self, eventCallback, filter);
}

void PikaStdDevice_GPIO_close(PikaObj* self) {
    pika_dev* dev = _get_dev(self);
    pika_hal_close(dev);
}

// class GPIO_ENUM
void PikaStdDevice_GPIO_ENUM___init__(PikaObj* self) {

    obj_setInt(self, "RISING", PIKA_HAL_GPIO_EVENT_SIGNAL_RISING);
    obj_setInt(self, "FALLING", PIKA_HAL_GPIO_EVENT_SIGNAL_FALLING);
    obj_setInt(self, "ANY", PIKA_HAL_GPIO_EVENT_SIGNAL_ANY);
    obj_setInt(self, "BOTH", PIKA_HAL_GPIO_EVENT_SIGNAL_ANY);

    obj_setInt(self, "NONE", PIKA_HAL_GPIO_PULL_NONE);
    obj_setInt(self, "UP", PIKA_HAL_GPIO_PULL_UP);
    obj_setInt(self, "DOWN", PIKA_HAL_GPIO_PULL_DOWN);

    obj_setInt(self, "OD", PIKA_HAL_GPIO_OPEN_DRAIN);
    obj_setInt(self, "OUT", PIKA_HAL_GPIO_DIR_OUT);
    obj_setInt(self, "IN", PIKA_HAL_GPIO_DIR_IN);
    obj_setInt(self, "IRQ", PIKA_HAL_GPIO_IRQ);

    obj_setInt(self, "LOW", PIKA_HAL_GPIO_LV_LOW);
    obj_setInt(self, "HIGH", PIKA_HAL_GPIO_LV_HIGH);


}